#include "log.h"

namespace hps {

LogEvent::LogEvent(std::shared_ptr<Logger> logger,
                   const char *file,
                   uint64_t time,
                   uint32_t line,
                   LogLevel::Level level) {
    m_file = file;
    m_time = time;
    m_line = line;
    m_level = level;
    m_logger = logger;
}

void Logger::unknow(LogEvent::ptr event) {
    log(LogLevel::UNKNOW, event);
}

void Logger::debug(LogEvent::ptr event) {
    log(LogLevel::DEBUG, event);
}

void Logger::info(LogEvent::ptr event) {
    log(LogLevel::INFO, event);
}

void Logger::warnning(LogEvent::ptr event) {
    log(LogLevel::WARNNING, event);
}

void Logger::fatal(LogEvent::ptr event) {
    log(LogLevel::FATAL, event);
}

void Logger::error(LogEvent::ptr event) {
    log(LogLevel::ERROR, event);
}

void Logger::log(LogLevel::Level level, LogEvent::ptr event) {
    reopen();
    m_fileStream << event -> format();
}

bool Logger::reopen() {
    if (m_fileStream) {
        m_fileStream . close();
    }
    m_fileStream . open(m_fileName, std::ios::app);
    return !!m_fileStream;
}

Logger::Logger() {

}

void Logger::setFile(std::string file) {
    m_fileName = file;
    m_fileStream . open(m_fileName, std::ios::app);
}

void LogEvent::format(const char *fmt, ...) {
    va_list al;
    va_start (al, fmt);
    format(fmt, al);
    va_end(al);
}

void LogEvent::format(const char *fmt, va_list vaList) {
    char *buf = nullptr;
    int len = vasprintf(&buf, fmt, vaList);
    if (len != -1) {
        m_ss << std::string(buf, len);
        free(buf);
    }
}

std::string LogEvent::format() {
    std::string formatter = "[%L]%t[%T]%t%F:%l%t%C%n", log = "";
    int idx = 0;
    int s = formatter . size();
    while (idx < s) {
        if (formatter[idx] == '%') {
            idx++;
            switch (formatter[idx]) {
                case 'L':
                    log += LogLevel::ToString(m_level);
                    break;
                case 't':
                    log += '\t';
                    break;
                case 'T':
                    log += TimeFormat(m_time);
                    break;
                case 'F':
                    log += std::string(m_file);
                    break;
                case 'l':
                    log += std::to_string(m_line);
                    break;
                case 'C':
                    log += m_ss . str();
                    break;
                case 'n':
                    log += '\n';
                    break;
                default:
                    log += formatter[idx];
                    break;
            }
            idx++;
        }
        else {
            log += formatter[idx++];
        }
    }
    return log;
}

const char *LogLevel::ToString(LogLevel::Level level) {
    switch (level) {
        case DEBUG:
            return "DEBUG";
        case INFO:
            return "INFO";
        case WARNNING:
            return "WARNNING";
        case ERROR:
            return "ERROR";
        case FATAL:
            return "FATAL";
        default:
            return "UNKNOW";
    }
}

LogLevel::Level LogLevel::FromString(std::string &str) {
#define XX(level, val) \
        if (str == #val)   \
            return LogLevel::level;

    XX(DEBUG, debug);
    XX(INFO, info);
    XX(WARNNING, warn);
    XX(ERROR, error);
    XX(FATAL, fatal);

    XX(DEBUG, DEBUG);
    XX(INFO, INFO);
    XX(WARNNING, WARN);
    XX(ERROR, ERROR);
    XX(FATAL, FATAL);
    return LogLevel::UNKNOW;
#undef XX
}

LogEventWarp::LogEventWarp(LogEvent::ptr event, LogLevel::Level level)
    : m_event(event), m_level(level) {

}

std::stringstream &LogEventWarp::getSS() {
    return m_event -> getSS();
}

LogEventWarp::~LogEventWarp() {
    m_event -> getLogger() -> log(m_level, m_event);
}

LoggerManager::LoggerManager() {
    m_root . reset(new Logger()); // 开辟一个logger
    m_root -> setFile("/home/hps/hps/Markdown-cpp/logs/log.log");
}
}